package com.semp.gu.codec.img;

import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JPanel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.semp.gu.codec.AbstractCodec;
import com.semp.gu.config.IConfigurationManager;
import com.semp.gu.domain.local.LocalAlbumElement;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGEncodeParam;
import com.sun.image.codec.jpeg.JPEGImageEncoder;

public class ImageCodec extends AbstractCodec {

	private ImageCodecConfiguration	configuration;
	private ImageCodecConfiguration	defaultConfiguration;
	private IConfigurationManager	configurationManager;

	private final static Logger		logger	= LoggerFactory.getLogger(ImageCodec.class);
	private JPanel					fooPanel;

	public ImageCodec() {
		super("img");
		fooPanel = new JPanel();
	}

	public void processElement(LocalAlbumElement element) throws IOException {
		int MAX_SIZE = configuration.getImageMaxSize();
		logger.info("Processing image {}", element.getName());
		File convertedFile = null;

		/*
		 * Image size calculation
		 */
		int imgWidth, imgHeight;
		Image image = (Image) ImageIO.read(element.getFile());
		MediaTracker mTracker = new MediaTracker(fooPanel);
		mTracker.addImage(image, 1);
		try {
			mTracker.waitForID(1);
		} catch (InterruptedException e) {
			logger.error("", e);
		}
		imgWidth = image.getWidth(null);
		imgHeight = image.getHeight(null);
		logger.debug("Image size {}x{}", imgWidth, imgHeight);

		/*
		 * Image processing
		 */
		if (Math.max(Math.max(imgWidth, imgHeight), MAX_SIZE) == MAX_SIZE) {
			logger.debug("Image is undersized, no conversion needed");
			convertedFile = element.getFile();
		} else {
			// image is bigger, conversion needed
			if (imgWidth > imgHeight) {
				imgHeight = imgHeight * MAX_SIZE / imgWidth;
				imgWidth = MAX_SIZE;
			} else {
				imgWidth = imgWidth * MAX_SIZE / imgHeight;
				imgHeight = MAX_SIZE;
			}
			logger.debug("Image will be resized to {}x{}", imgWidth, imgHeight);
			convertedFile = scaleImage(element.getFile(), imgWidth, imgHeight);
		}

		/*
		 * Return
		 */
		element.getConvertedFileList().add(convertedFile);
		logger.info("Image {} converted into {}", element.getName(), convertedFile.getAbsolutePath());
	}

	/*
	 * IO image scaling
	 */
	private File scaleImage(File inputFile, int width, int height) throws IOException {
		Image image = (Image) ImageIO.read(inputFile);
		File convertedFile = new File(getWorkingFolder() + File.separator + inputFile.getName());

		// Draw the scaled image
		BufferedImage scaledImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
		Graphics2D graphics2D = scaledImage.createGraphics();
		graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
		graphics2D.drawImage(image, 0, 0, width, height, null);

		// Write the scaled image to the outputstream
		JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(new FileOutputStream(convertedFile));
		JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(scaledImage);
		param.setQuality((float) configuration.getJpgCompressionQuality() / 100.0f, false);
		encoder.setJPEGEncodeParam(param);
		encoder.encode(scaledImage);
		ImageIO.write(scaledImage, "jpg", encoder.getOutputStream());

		return convertedFile;
	}

	// Getters & Setters
	
	private void loadConfiguration(IConfigurationManager configurationManager, ImageCodecConfiguration defaultConfiguration) throws IOException {
		if (configurationManager != null && defaultConfiguration != null) {
			configuration = (ImageCodecConfiguration) configurationManager.loadConfiguration(defaultConfiguration);
		}
	}

	public ImageCodecConfiguration getDefaultConfiguration() {
		return defaultConfiguration;
	}

	public void setDefaultConfiguration(ImageCodecConfiguration defaultConfiguration) throws IOException {
		this.defaultConfiguration = defaultConfiguration;
		loadConfiguration(configurationManager, defaultConfiguration);
	}

	public IConfigurationManager getConfigurationManager() {
		return configurationManager;
	}

	public void setConfigurationManager(IConfigurationManager configurationManager) throws IOException {
		this.configurationManager = configurationManager;
		loadConfiguration(configurationManager, defaultConfiguration);
	}
	
}
